package cn.geminis.warehouse.service.purchase.controller;

import cn.geminis.warehouse.service.purchase.entity.Purchase;
import cn.geminis.warehouse.service.purchase.entity.PurchaseDetail;
import cn.geminis.warehouse.service.purchase.entity.PurchaseState;
import cn.geminis.warehouse.service.purchase.entity.filter.PurchaseCheckFailedFilter;
import cn.geminis.warehouse.service.purchase.entity.repository.PurchaseCheckFailedRepository;
import cn.geminis.warehouse.service.purchase.entity.repository.PurchaseDetailRepository;
import cn.geminis.workflow.client.Approve;
import cn.geminis.workflow.client.WorkflowClient;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

public class PurchaseController {

//    private final String PROCESS_KEY = "wh_purchase";
//    private final String TASK_DELIVERY_KEY = "wh_purchase_delivery";
//    private final String TASK_ARRIVE_KEY = "wh_purchase_arrive";
//    private final String TASK_RECEIVE_KEY = "wh_purchase_receive";
//    private final String TASK_CHECK_KEY = "wh_purchase_check";
//    private final String TASK_PACKAGE_KEY = "wh_purchase_package";

//    private final WorkflowClient workflowClient;
    private final PurchaseDetailRepository purchaseDetailRepository;
    private final PurchaseCheckFailedRepository purchaseCheckFailedRepository;

//    private void completeTask(String taskKey, String[] ids) {
//        Arrays.stream(ids).forEach(id -> {
//            workflowClient.taskAssignee(id, null);
//            workflowClient.taskComplete(
//                    Approve.builder()
//                            .result("agree")
//                            .taskKey(taskKey)
//                            .businessKey(id)
//                            .build());
//        });
//    }

    @PostMapping
    @Transactional(rollbackFor = Exception.class)
    public void save(@RequestBody Purchase object) {
        var details = new HashMap<String, PurchaseDetail>();
        for (var detail : object.getDetails()) {
            var exist = details.get(detail.getProductBatch().getId());
            if (ObjectUtils.isEmpty(exist)) {
                details.put(detail.getProductBatch().getId(), detail);
            } else {
                exist.setAmount(exist.getAmount() + detail.getAmount());
                detail.setAmount(0);
            }
            detail.setPurchase(object);
        }
        for (var route : object.getRoutes()) {
            route.setPurchase(object);
        }
        object.getDetails().removeIf(detail -> detail.getAmount() == 0 && ObjectUtils.isEmpty(detail.getId()));
        object.getDetails().forEach(detail -> {
            if (detail.getAmount() == 0) {
                this.purchaseDetailRepository.delete(detail);
                object.getDetails().remove(detail);
            }
        });
//        var newPurchase = ObjectUtils.isEmpty(object.getId());
        this.repository.save(object);
//        if (newPurchase) {
//            workflowClient.processStart(PROCESS_KEY, object.getId(), object);
//        }

        object.getDetails().stream().map(detail -> detail.getAmount()).reduce(0, Integer::sum);
    }

    @DeleteMapping
    @Transactional(rollbackFor = Exception.class)
    public void delete(@RequestBody List<String> ids) {
        ids.forEach((id) -> {
            this.repository.deleteById(id);
//            workflowClient.processStop(PROCESS_KEY, id);
        });
    }

    @PostMapping("/delivery")
    @Transactional(rollbackFor = Exception.class)
    public void delivery(@RequestParam String[] ids, @RequestParam String time) {
        this.repository.delivery(LocalDate.parse(time, DateTimeFormatter.ofPattern("yyyy-MM-dd")), ids);
//        completeTask(TASK_DELIVERY_KEY, ids);
    }

    @PostMapping("/arrive")
    @Transactional(rollbackFor = Exception.class)
    public void arrive(@RequestParam String[] ids, @RequestParam String time) {
        this.repository.arrive(LocalDate.parse(time, DateTimeFormatter.ofPattern("yyyy-MM-dd")), ids);
//        completeTask(TASK_ARRIVE_KEY, ids);
    }

    @PostMapping("/receive")
    @Transactional(rollbackFor = Exception.class)
    public void receive(@RequestParam String[] ids, @RequestParam String time) {
        this.repository.receive(LocalDate.parse(time, DateTimeFormatter.ofPattern("yyyy-MM-dd")), ids);
//        completeTask(TASK_RECEIVE_KEY, ids);
    }

    @PostMapping("/check")
    @Transactional(rollbackFor = Exception.class)
    public void check(@RequestParam String[] ids, @RequestParam String time) {
        var checkTime = LocalDate.parse(time, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        Arrays.stream(ids).forEach(id -> {
            var purchase = this.repository.findById(id).get();
            var failed = purchaseCheckFailedRepository
                    .findAll(
                            PurchaseCheckFailedFilter.builder()
                                    .purchaseId(id)
                                    .build()
                    );
            failed.forEach(f -> {
                purchase.getDetails().stream()
                        .filter(d -> d.getProductBatch().getId() == f.getProductBatch().getId())
                        .findAny()
                        .ifPresent(d -> {
                            d.setAmountCheck(d.getAmountScan() - f.getAmount());
                        });
            });
            purchase.setState(PurchaseState.CHECK);
            purchase.setCheckTime(checkTime);
            repository.save(purchase);
        });
//        completeTask(TASK_CHECK_KEY, ids);
    }

    @PostMapping("/pack")
    @Transactional(rollbackFor = Exception.class)
    public void pack(@RequestParam String[] ids, @RequestParam String time) {
        this.repository.pack(LocalDate.parse(time, DateTimeFormatter.ofPattern("yyyy-MM-dd")), ids);
//        completeTask(TASK_PACKAGE_KEY, ids);
    }

}
